package SIC.Controleur.Mapping;

import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.AddAxiom;
import org.semanticweb.owlapi.model.AddImport;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLEquivalentClassesAxiom;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.semanticweb.owlapi.model.PrefixManager;
import org.semanticweb.owlapi.util.DefaultPrefixManager;

/**
 * Cette classe fait le mapping entre les fichiers OWL du CAO et du FAO
 */
public class Mapping {

	private OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
	private CorrespondancesCaoFao correspondances;
	
	//Les préfixes utiles
	private PrefixManager prefixeCAO;
	private PrefixManager prefixeFAO;
	
	//Propriétés de compmositions dans CAO et FAO
	private OWLObjectProperty CAOestComposeDe;
	private OWLObjectProperty FAOestComposeDe;
	
	OWLDataFactory dataFactory;
	
	//La nouvelle ontologie pour les correspondances
	OWLOntology ontologyCAOFAO;
	
	public Mapping(CorrespondancesCaoFao correspondances)
	{
		this.correspondances = correspondances;
	}
	
	
	/**
	 * Fait le mapping entre les fichiers OWL du CAO et du FAO.
	 * Génère un nouveau fichier de correspondances au format OWL.
	 * 
	 * @param iriCAOFAO iri du nouveau fichier CAO_FAO, exemple : http://www.stylo.com/CAO_FAO/
	 * @param owlCAOFAO nom du fichier OWL du CAO_FAO 
	 * @param iriCAO iri du fichier CAO, exemple : http://www.stylo.com/CAO/
	 * @param owlCAO nom du fichier OWL du CAO
	 * @param iriFAO iri du fichier FAO, exemple : http://www.stylo.com/FAO/
	 * @param owlFAO nom du fichier OWL du FAO
	 */
	public void creerOWLMapping(IRI iriCAOFAO, String owlCAOFAO, IRI iriCAO, String owlCAO, IRI iriFAO, String owlFAO)
	{
		OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
		
		File fichierOWLCAO = new File(owlCAO);
		File fichierOWLFAO = new File(owlFAO);
		File fichierOWLCAOFAO = new File(owlCAOFAO);
		
		try {
			
			//On charge les deux ontologies CAO et FAO
			OWLOntology ontologyCAO = manager.loadOntologyFromOntologyDocument(fichierOWLCAO);
			OWLOntology ontologyFAO = manager.loadOntologyFromOntologyDocument(fichierOWLFAO);
			
			//On crée notre ontologie de mapping
			ontologyCAOFAO = manager.createOntology(iriCAOFAO);
			
			//On récupère la fabrique
			dataFactory = manager.getOWLDataFactory();

			/*
			 * On fait les bons imports
			 * C'est obligatoire ! OWL Api ne le fait pas tout seul :s
			 */
			manager.applyChange(new AddImport(ontologyCAOFAO, dataFactory.getOWLImportsDeclaration(iriCAO)));
			manager.applyChange(new AddImport(ontologyCAOFAO, dataFactory.getOWLImportsDeclaration(iriFAO)));
			
			prefixeCAO = new DefaultPrefixManager(iriCAO.toString());
			prefixeFAO = new DefaultPrefixManager(iriFAO.toString());

			//On récupère les propriétés de composition du CAO et du FAO
			CAOestComposeDe = ontologyCAO.getObjectPropertiesInSignature().iterator().next();
			FAOestComposeDe = ontologyFAO.getObjectPropertiesInSignature().iterator().next();

			//On parcours les correspondances CAO tel que CAO:... = FAO:... + FAO:...
			creerCorrespondances(correspondances.getCorrespondancesCAO(), prefixeCAO, prefixeFAO, CAOestComposeDe, FAOestComposeDe);
			
			//On parcours les correspondances FAO tel que FAO:... = CAO:... + CAO:...
			creerCorrespondances(correspondances.getCorrespondancesFAO(), prefixeFAO, prefixeCAO, FAOestComposeDe, CAOestComposeDe);

			manager.saveOntology(ontologyCAOFAO, IRI.create(fichierOWLCAOFAO.toURI()));

		} catch (OWLOntologyCreationException e) {
			e.printStackTrace();
		} catch (OWLOntologyStorageException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * Traite chacune des correspondance de la map
	 * @param corr map de correspondances
	 * @param pGauche Par exemple, si on traite une correspondance "CAO:... = FAO:... + ...", alors pGauche = prefixeCAO
	 * @param pDroite Par exemple, si on traite une correspondance "CAO:... = FAO:... + ...", alors pDroite = prefixeFAO
	 */
	private void creerCorrespondances(Map<String, List<String>> corr,
									  PrefixManager pGauche,
									  PrefixManager pDroite,
									  OWLObjectProperty estComposeDeGauche,
									  OWLObjectProperty estComposeDeDroite)
	{
		for(Entry<String, List<String>> entry : corr.entrySet())
		{
			OWLClass produitGauche = dataFactory.getOWLClass(entry.getKey(), pGauche);
			
			List<String> produitsFAO = entry.getValue();
			
			if(produitsFAO.size() == 1) //http://www.w3.org/TR/owl-ref/#equivalentClass-def
			{
				OWLClass produitDroite = dataFactory.getOWLClass(produitsFAO.get(0), pDroite);
				
				OWLClassExpression hasPartSomeProduit = dataFactory.getOWLObjectSomeValuesFrom(estComposeDeDroite, produitDroite);
				
				OWLEquivalentClassesAxiom equiAxiome = dataFactory.getOWLEquivalentClassesAxiom(produitGauche, hasPartSomeProduit);
				AddAxiom addAx1 = new AddAxiom(ontologyCAOFAO, equiAxiome);	
				manager.applyChange(addAx1);
			}
			else //http://www.w3.org/TR/owl-ref/#subClassOf-def
			{
				for(String nomProduitFAO : produitsFAO)
				{
					OWLClass produitDroite = dataFactory.getOWLClass(nomProduitFAO, pDroite);
					OWLClassExpression hasPartSomeProduit = dataFactory.getOWLObjectSomeValuesFrom(estComposeDeDroite, produitDroite);
					OWLSubClassOfAxiom axiome = dataFactory.getOWLSubClassOfAxiom(produitGauche, hasPartSomeProduit);
					AddAxiom addAx = new AddAxiom(ontologyCAOFAO, axiome);	
					manager.applyChange(addAx);
				}
			}
		}
	}
	

}
